#include "Database.h"

Database::Database()
{
	mp_Result = nullptr;
	mp_host = nullptr;
	mp_user = nullptr;
	mp_pwd = nullptr;
	mp_db = nullptr;

	m_isInit = 	false;
	m_isConnect = false;

	m_row = 0;
	m_cols = 0;
	//ctor
}

Database::~Database()
{
	mp_Result = nullptr;
	mp_host = nullptr;
	mp_user = nullptr;
	mp_pwd = nullptr;
	mp_db = nullptr;
	//dtor
}

// 初始化
int Database::Init(string host, string user, string pwd, string db)
{
	mp_host = (char*)host.c_str();
	mp_user = (char*)user.c_str();
	mp_pwd = (char*)pwd.c_str();
	mp_db = (char*)db.c_str();

	// 初始化
	if(NULL == mysql_init(&m_Mysql))
	{
		Debug::Error(__func__, " mysql_init error");
		return -1;
	}

	// 链接
	if(0 != this->Connect())
	{
		return -1;
	}

	m_isInit = true;

	this->LoadInit();

	return 0;
}

// 释放
void Database::Dispose()
{
	if(!m_isInit){
		return;
	}


	SaveAll();

	// 释放结果集
	if(mp_Result != nullptr)
	{
		mysql_free_result(mp_Result);
	}

	// 关闭
	mysql_close(&m_Mysql);
	Debug::State("Close the database:", mp_db, " connect.");
	return;
}

void Database::SaveAll()
{
	Debug::Log("Database::SaveAll. YU_TODO:");

}

// 链接
int Database::Connect()
{
	if(m_isConnect)
	{
		Debug::Error("The database ", mp_db, "con't connected. Already connected before.");
		return -1;
	}

	if(!mysql_real_connect(&m_Mysql, mp_host, mp_user, mp_pwd, mp_db, 0, nullptr, 0))
	{
		Debug::Error("When connect database, info: ", mysql_error(&m_Mysql));
		return -1;
	}

	Debug::State("Connect database succeed.");
	m_isConnect = true;
	return 0;
}

// 表 查询
int Database::Query(string sql)
{
	if(!m_isInit)
	{
		Debug::Error("Run sql error. please init database.");
		return -1;
	}

	if(-1 == this->RunSql(sql))
	{
		Debug::Error("Database ", mp_host, " Query error.");
		return -1;
	}

	mp_Result = mysql_store_result(&m_Mysql);

	// 打印获取数据行数 和 列数
	m_row = mysql_num_rows(mp_Result);
	m_cols = mysql_num_fields(mp_Result);
	Debug::Log("U got row:", m_row, " cols:", m_cols, " records.");

//	// 查询
//	MYSQL_RES* Res = nullptr;
//	const char* sql2 = "SELECT * FROM tUser;";
//	if(0 != mysql_query(&mysql, sql2)){
//		cout<< "excute sql error. please check your SQL syntax. 1"<< endl;
//		return 0;
//	}
//	Res = mysql_store_result(&mysql);
//	cout<< "query succeed."<< endl;
//
//	// 打印查询结果
//	// 打印获取数据行数
//	int rowCount = mysql_num_rows(Res);
//	cout<< "u got "<< rowCount<< "records."<< endl;
//
//	// 遍历列
//	int fieldCount = mysql_num_fields(Res);
//	cout<< "cols: "<< fieldCount<< endl;
//	MYSQL_FIELD *Feild = nullptr;
//	for(int i = 0; i < fieldCount; i++){
//		Feild = mysql_fetch_field_direct(Res, i);
//		cout<< Feild->name<< "\t\t";
//	}
//	cout<<endl;
//
//	// 遍历行
//	MYSQL_ROW Row = nullptr;
//	while(NULL != (Row = mysql_fetch_row(Res)))
//	{
//			for(int i = 0; i < rowCount; i++)
//			{
//				cout<< Row[i]<< "\t\t";
//			}
//			cout<< endl;
//	}
//	cout<< "show data over."<< endl;

	return m_row;
}

// 表 添加
int Database::Insert(string sql)
{
	if(!m_isInit)
	{
		Debug::Error("Insert sql error. Please init database.");
		return -1;
	}

	if(-1 == this->RunSql(sql))
	{
		Debug::Error("DB ", mp_db, " Insert error. sql:", sql);
		return -1;
	}

	return 0;
}

// 表 删除
int Database::Drop(string sql)
{
	if(!m_isInit)
	{
		Debug::Error("Run sql error. Please init database.");
		return -1;
	}

	if(-1 == this->RunSql(sql))
	{
		Debug::Error("Database ", mp_db, "Drop error.");
		return -1;
	}

	return 0;
}

// 表 更新
int Database::Update(string sql)
{
	if(!m_isInit)
	{
		Debug::Error("Run sql error. Please init database.");
		return -1;
	}

	if(-1 == this->RunSql(sql))
	{
		Debug::Error("Database ", mp_db, "Update error.");
		return -1;
	}
	return 0;
}

// 执行sql语句
int Database::RunSql(string sql)
{
	if(!m_isInit)
	{
		Debug::Error("Run sql error. Please init database.");
		return -1;
	}

	char* sqlStr = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sqlStr)){
		Debug::Error("Run sql error. Please check your SQL syntax, your sql:\n", sql);
		return -1;
	}

	return 0;
}

bool Database:: LoadInit()
{
	LoadGlobal();

	return true;
}

int Database::LoadGlobal()
{
	// 缓存中没有 就从数据库中查找
	string tableName = "tGlobal";
	string sql = "SELECT * FROM " + tableName +";";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error(tableName, " load error. pls check your SQL syntax. sql:", sql);
		return -1;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);

	MYSQL_ROW Row = nullptr;
	while(NULL != (Row = mysql_fetch_row(Res)))
	{
		tGlobal Data1;
		Data1.id = std::atoi(Row[0]);
		Data1.key = std::atoi(Row[1]);
		Data1.value = std::atoi(Row[2]);

		m_GlobalMap[Data1.key] = Data1;
	}

	Debug::Log(tableName, " Load Finished. count:", rowCount);
	return rowCount;
}

bool Database::IsFindGlobal(int _key)
{
	// 缓存中是否存在
	map<int, tGlobal>::iterator iter;
	for(iter = m_GlobalMap.begin();iter != m_GlobalMap.end(); iter++)
	{
		if(iter->second.key == _key)
			return true;
	}

	// 缓存中没有 就从数据库中查找
	string tableName = "tGlobal";
	string sql = "SELECT * FROM "+ tableName +" WHERE key='" + Common::itos(_key) + "';";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error("SelectUser() excute sql error. please check your SQL syntax. 1");
		return false;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);

	Debug::Log("SelectUser() rowCount:", rowCount);
	return(rowCount != 0);
}

tGlobal* Database::SelectGlobal(int _key)
{
// 缓存中有 就从缓存中直接返回
	map<int, tGlobal>::iterator iter;
	for(iter = m_GlobalMap.begin();iter != m_GlobalMap.end(); iter++)
	{
		if(iter->second.key == _key)
		{
			return &(iter->second);
		}
	}

	// 缓存中没有 就从数据库中查找
	string tableName = "tGlobal";
	string sql = "SELECT * FROM " + tableName +" WHERE key='" + Common::itos(_key) + "';";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error("SelectGlobal() excute sql error. sql:", sql);
		return nullptr;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);
	if(rowCount != 1)
	{
		Debug::Error("SelectGlobal() error. rowCount != 1, rowCount:", rowCount);
		return nullptr;
	}

	MYSQL_ROW Row = nullptr;
	int id = 0;
	while(NULL != (Row = mysql_fetch_row(Res)))
	{
		tGlobal Data1;
		Data1.id = std::atoi(Row[0]);
		Data1.key = std::atoi(Row[1]);
		Data1.value = std::atoi(Row[2]);

		id = Data1.key;
		m_GlobalMap[id] = Data1;
	}

	return &m_GlobalMap[id];
}

int Database::InsertGlobal(const tGlobal& _Global)
{
	string tName = "tGlobal";
	string sql = "INSERT INTO "+ tName + " VALUES("
		+ Common::itos(_Global.id) + ","
		+ Common::itos(_Global.key) + ","
		+ Common::itos(_Global.value) +");";

	int ret = Insert(sql);
	if(ret != 0)
	{
		Debug::Error(__func__, " ret != 0. ret:", ret);
	}

	Debug::State("Database::InsertGlobal, ret:", ret);
	m_GlobalMap[_Global.key] = _Global;
	return ret;
}

bool Database::UpdateGlobal(const tGlobal& _Global)
{
	if(m_GlobalMap.count(_Global.key) == 0)
	{
		if(0 != InsertGlobal(_Global))
			return false;

		return true;
	}

	// YU_TODO: 临时save 直接在更新的时候就写入数据库 最好只更新内存 然后SaveAll的时候 一次更新表
	string table = "tGlobal";
	string sql = "UPDATE " + table +  " SET tGlobal.value=" + Common::itos(_Global.value)
		+ " WHERE tGlobal.key=" +  Common::itos(_Global.key) + ";";
	int ret = RunSql(sql);
	if(ret != 0)
	{
		return false;
	}

	m_GlobalMap[_Global.key].value = _Global.value;
	return true;
}

const map<int, tGlobal>& Database::GetGlobalMap()
{
	return this->m_GlobalMap;
}

tUser* Database::SelectUser(string _user)
{
	// 缓存中有 就从缓存中直接返回
	map<int, tUser>::iterator iter;
	for(iter = m_UserMap.begin();iter != m_UserMap.end(); iter++)
	{
		if(iter->second.user == _user)
		{
			return &(iter->second);
		}
	}

	// 缓存中没有 就从数据库中查找
	string sql = "SELECT * FROM tUser WHERE user='" + _user + "';";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error("SelectUser() excute sql error. sql:", sql);
		return nullptr;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);
	if(rowCount != 1)
	{
		Debug::Error("SelectUser() excute sql error. rowCount != 1, rowCount:", rowCount);
		return nullptr;
	}

	MYSQL_ROW Row = nullptr;
	int id = 0;
	while(NULL != (Row = mysql_fetch_row(Res)))
	{
		tUser User1;
		User1.id = std::atoi(Row[0]);
		User1.user = string(Row[1]);
		User1.pwd =  string(Row[2]);

		id = User1.id;
		m_UserMap[id] = User1;
	}

	return &m_UserMap[id];
}

bool Database::IsFindUser(string _user)
{
	// 缓存中是否存在
	map<int, tUser>::iterator iter;
	for(iter = m_UserMap.begin();iter != m_UserMap.end(); iter++)
	{
		if(iter->second.user == _user)
			return true;
	}

	// 缓存中没有 就从数据库中查找
	string sql = "SELECT * FROM tUser WHERE user='" + _user + "';";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error("IsFindUser() excute sql error. sql:", sql);
		return false;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);

	Debug::Log("IsFindUser() rowCount:", rowCount);
	return(rowCount != 0);
}

// 插入用户 返回0:成功
int Database::InsertUser(const tUser& _User)
{
	string tName = "tUser";
	string sql = "INSERT INTO " + tName + " VALUES(" +
		Common::itos(_User.id) + ",'" + _User.user + "','" + _User.pwd +"');";

	int ret = Insert(sql);
	if(ret == 0)
	{
		m_UserMap[_User.id] = _User;
	}

	return ret;
}

tPlayer* Database::SelectPlayer(int _id)
{
	// 缓存中有 就从缓存中直接返回
	if(m_PlayerMap.count(_id) != 0)
		return &m_PlayerMap[_id];

	// 缓存中没有 就从数据库中查找
	string sql = "SELECT * FROM tPlayer WHERE userId=" + Common::itos(_id)  + ";";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error("SelectUser() excute sql error. sql:", sql);
		return nullptr;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);
	if(rowCount != 1)
	{
		Debug::Error("SelectUser() excute sql error. rowCount != 1, rowCount:", rowCount);
		return nullptr;
	}

	MYSQL_ROW Row = nullptr;
	int id = 0;
	while(NULL != (Row = mysql_fetch_row(Res)))
	{
		int id = std::atoi(Row[0]);
		CachePlayer(Row);
	}

	return &m_PlayerMap[id];
}

bool Database::CachePlayer(MYSQL_ROW Row)
{
	int id = std::atoi(Row[0]);
	if(m_PlayerMap.count(id) > 0)
	{
		Debug::Warn(__func__, " Alreay in DBCache id:", id);
		return false;
	}

	tPlayer DB;
	DB.id = std::atoi(Row[0]);
	DB.userId = std::atoi(Row[1]);
	DB.sex = std::atoi(Row[2]);
	DB.silver = std::atoi(Row[3]);
	DB.gold = std::atoi(Row[4]);
	DB.diamond = std::atoi(Row[5]);
	DB.birthtime = std::atol(Row[6]);
	DB.name = string(Row[7]);
	DB.desc = string(Row[8]);
	DB.roleId = std::atoi(Row[9]);
	DB.aryId = std::atoi(Row[10]);

	m_PlayerMap[DB.id] = DB;
	return true;
}

tPlayer* Database::SelectPlayerByUserId(int _userId)
{
	// 缓存中有 就从缓存中直接返回
	map<int, tPlayer>::iterator iter;
	for(iter = m_PlayerMap.begin();iter != m_PlayerMap.end(); iter++)
	{
		if(iter->second.userId == _userId)
		{
			return &(iter->second);
		}
	}

	// 缓存中没有 就从数据库中查找
	string sql = "SELECT * FROM tPlayer WHERE userId=" + Common::itos(_userId)  + ";";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error("SelectUser() excute sql error. sql:", sql);
		return nullptr;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);
	if(rowCount != 1)
	{
		Debug::Warn("SelectUser(). rowCount != 1, rowCount:", rowCount);
		return nullptr;
	}

	MYSQL_ROW Row = nullptr;
	int id = 0;
	while(NULL != (Row = mysql_fetch_row(Res)))
	{
		id = std::atoi(Row[0]);
		CachePlayer(Row);
	}

	return &m_PlayerMap[id];
}

// 插入数据 0:成功 -1:插入失败
int Database::InsertPlayer(const tPlayer& _tData)
{
	string tName = "tPlayer";
	string sql = "INSERT INTO " + tName + " VALUES("
		+ Common::itos( _tData.id )
		+ "," + Common::itos(_tData.userId)
		+ "," + Common::itos(_tData.sex)
		+ "," + Common::itos(_tData.silver)
		+ "," + Common::itos(_tData.gold)
		+ "," + Common::itos(_tData.diamond)
		+ "," + Common::ltos(_tData.birthtime)
		+ ",'" + _tData.name
		+ "','" + _tData.desc
		+ "'," + Common::itos(_tData.roleId)
		+ "," + Common::itos(_tData.aryId)
		+ ");";

	int ret = Insert(sql);
	if(ret == 0)
	{
		m_PlayerMap[_tData.id] = _tData;
	}

	return ret;
}

bool Database::UpdatePlayer(const tPlayer& _Player)
{
	return true;
}

bool Database::IsExistPlayer(int _playerId)
{
	// 如果缓存中有
	if(m_PlayerMap.count(_playerId) >0)
		return true;

	string table = "tPlayer";

	// 如果数据库中有
	string sql = "SELECT * FROM " + table + " WHERE id=" + Common::itos(_playerId) + ";";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error(__func__, "() excute sql error. sql:", sql);
		return true;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);

	Debug::Log("IsFindUser() rowCount:", rowCount);

	if(rowCount == 1)
	{
		MYSQL_ROW Row = nullptr;
		while(NULL != (Row = mysql_fetch_row(Res)))
		{
			CachePlayer(Row);
		}
	}
	return(rowCount != 0);

}

bool Database::IsExistRole(int _roleId)
{
	// 如果缓存中有
	if(m_RoleMap.count(_roleId) >0)
		return true;

	string table = "tRole";

	// 如果数据库中有
	string sql = "SELECT * FROM " + table + " WHERE id=" + Common::itos(_roleId) + ";";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error(__func__, "() excute sql error. sql:", sql);
		return true;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);

	// 如果数据库中有 则应该缓存到内存中
	if(rowCount == 1)
	{
		MYSQL_ROW Row = nullptr;
		while(NULL != (Row = mysql_fetch_row(Res)))
		{
			CacheRole(Row);
		}
	}

	return(rowCount != 0);
}

// 插入数据 0:成功 -1:插入失败
int Database::InsertRole(const tRole& _tData)
{
	string tName = "tRole";
	string sql = "INSERT INTO " + tName + " VALUES("
		+ Common::itos(_tData.id)
		+ "," + Common::itos(_tData.cfgId)
		+ "," + Common::itos(_tData.type)
		+ "," + Common::itos(_tData.lv)
		+ "," + Common::itos(_tData.exp)

		+ "," + Common::itos(_tData.hp)
		+ "," + Common::itos(_tData.countryId)
		+ "," + Common::itos(_tData.cityId)
		+ "," + Common::itos(_tData.buildId)
		+ "," + Common::itos(_tData.jobId)

		+ "," + Common::itos(_tData.houseId)
		+ ",'" + _tData.name
		+ "','" + _tData.desc
		+ "');";

	int ret = Insert(sql);
	if(ret == 0)
	{
		m_RoleMap[_tData.id] = _tData;
	}

	Debug::State("Database::InsertRole ret:", ret);
	return ret;
}

bool Database::CacheRole(MYSQL_ROW Row)
{
	int id = std::atoi(Row[0]);
	if(m_RoleMap.count(id) > 0)
	{
		Debug::Warn(__func__, " Alreay in DBCache id:", id);
		return false;
	}

	tRole DB;
	DB.id = std::atoi(Row[0]);
	DB.cfgId = std::atoi(Row[1]);
	DB.type = std::atoi(Row[2]);
	DB.lv = std::atoi(Row[3]);
	DB.exp = std::atoi(Row[4]);

	DB.hp = std::atoi(Row[5]);
	DB.countryId = std::atoi(Row[6]);
	DB.cityId = std::atoi(Row[7]);
	DB.buildId = std::atoi(Row[8]);
	DB.jobId = std::atoi(Row[9]);

	DB.houseId = std::atoi(Row[10]);
	DB.name = string(Row[11]);
	DB.desc = string(Row[12]);

	m_RoleMap[DB.id] = DB;
	return true;
}

tRole* Database::SelectRole(int _Id)
{
	if(m_RoleMap.count(_Id) > 0)
	{
		return &m_RoleMap[_Id];
	}

	// 缓存中没有 就从数据库中查找
	string table = "tRole";
	string sql = "SELECT * FROM " +table +" WHERE " + table+".id=" + Common::itos(_Id)  + ";";
	char* sql2 = (char*)sql.c_str();
	if(0 != mysql_query(&m_Mysql, sql2))
	{
		Debug::Error(__func__, "() error. sql:" + sql);
		return nullptr;
	}

	MYSQL_RES* Res = mysql_store_result(&m_Mysql);
	int rowCount = mysql_num_rows(Res);
	if(rowCount != 1)
	{
		Debug::Error(__func__, "()  error. rowCount != 1, rowCount:", rowCount);
		return nullptr;
	}

	MYSQL_ROW Row = nullptr;
	while(NULL != (Row = mysql_fetch_row(Res)))
	{
		CacheRole(Row);
	}

	return &m_RoleMap[_Id];
}
